﻿using ComLib.ComType;
using DetectProcessing.ComModel;
using LogLib;
using Newtonsoft.Json;
using ProcessConfig;
using ProcessConfig.ConfigType;
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

namespace DetectProcessing
{
    /// <summary>
    /// 像素处理流程
    /// </summary>
    public class PxlProcess
    {
        private PxlHandler _handler = null;

        private PhotoApplyOption _applyOption = new PhotoApplyOption();

        public PxlProcess(PhotoApplyOption option)
        {
            _applyOption = option;
            PxlAdjustOption adjustOpt = Configs.ADOpts[_applyOption.ApplyType];
            _handler = new PxlHandler(adjustOpt, _applyOption);
        }

        public PxlProcess(PxlHandler handler)
        {
            _handler = handler;
        }

        /// <summary>
        /// 对输入图像数据进行简单的面部特征识别，不裁剪不调色不去背景不检测质量
        /// </summary>
        /// <param name="srcIn"></param>
        /// <param name="detecRes"></param>
        /// <returns></returns>
        public void HandlePrimary(RecogIn srcIn, RecogOut detecRes)
        {
            detecRes.Reset();
            _handler.DetectFacePosition(srcIn, detecRes, true);
            if (detecRes.PassElems.Front)
            {
                Log.WriteAsync("正脸识别成功");
            }
            else
            {
                Log.WriteAsync("正脸识别失败:" + detecRes.Correction.Tips);
            }
        }

        /// <summary>
        /// 像素算法综合处理
        /// </summary>
        /// <param name="srcIn">输入照片</param>
        /// <param name="detecRes">输出参数集合</param>
        /// <returns></returns>
        public async Task<bool> Handle(RecogIn srcIn, RecogOut detecRes, int index = -1)
        {
            detecRes.Reset();
            _handler.Index = index;
            if (!_handler.PrepareForCroping(srcIn, detecRes))
            {
                Log.WriteAsync("正脸识别失败，PXL全处理中断...");
                return false;
            }
            try
            {
                _handler.SaveSourceData(srcIn, detecRes);
                if (index >= 0)
                {
                    if (await OnBKGCleaning(detecRes))
                    {
                        srcIn.LoadFromFile(detecRes.SourceImagePath);
                    }
                }

                if (!_handler.CropAndAdjust(srcIn, detecRes, index))
                {
                    detecRes.UnAcceptItem = UnAcceptableItem.Crop;
                    detecRes.Correction.Tips = "图像裁切失败";
                    Log.WriteAsync("PXL检测结果不通过: 图像裁切失败");
                    return false;
                }        
                
                return true;
            }
            catch (System.Exception e)
            {
                detecRes.UnAcceptItem = UnAcceptableItem.RunningException;              
                detecRes.Correction.Tips = "处理照片过程中发生了异常:" + e.Message;
                Log.WriteException(e.ToString());
                return false;
            }
        }

        private TcpClientOption _option = new TcpClientOption();

        private QuoteClient _client = null;

        private bool TcpConnected = false;

        private async Task OnConnected()
        {
            var config = Configs.TcpClient;
            _client = new QuoteClient(config.ServerIP, config.Port);
            _client.DataReceived += OnDataReceived;
            _client.Closed += OnClosed;
            TcpConnected = await _client.Connect();
            if (TcpConnected)
            {
                Log.WriteAsync("TCP连接成功.");
            }
            else
            {
                Log.WriteAsync("TCP连接失败");
            }
        }

        private void OnClosed(object sender, EventArgs e)
        {
            TcpConnected = false;
        }

        private ConcurrentDictionary<string, string> MapDestFiles = new ConcurrentDictionary<string, string>();

        private ManualResetEventSlim _waitEvent = new ManualResetEventSlim(false);

        private void OnDataReceived(object sender, DataReceivedEventArgs e)
        {
            string receiveData = e.Message;
            Log.WriteAsync($"receiveData: {receiveData}");
            try
            {
                ResponseInfo info = JsonConvert.DeserializeObject<ResponseInfo>(receiveData);
                var config = Configs.TcpClient;
                if (info.Result)
                {
                    MapDestFiles.TryAdd(info.Id, info.DestPhoto);
                    Log.WriteAsync($"对于id:{info.Id}, PaddleSeg处理背景成功:{info.DestPhoto}.");
                }    
                else
                {
                    Log.WriteAsync($"对于id:{info.Id},PaddleSeg处理背景失败:{info.Message}.");
                }
                _waitEvent.Set();
            }
            catch (Exception ex)
            {
                Log.WriteException(ex.ToString());
            }
        }

        private async Task<bool> OnBKGCleaning(RecogOut detecRes)
        {
            _waitEvent.Reset();
            if (!TcpConnected)
            {
                await OnConnected();
            }
            if (!TcpConnected)
            {
                return false;
            }         
            RequestInfo info = new RequestInfo();
            info.RequestTime = DateTime.Now;
            info.SourcePhoto = detecRes.SourceImagePath;
            info.Id = Guid.NewGuid().ToString();
            string jsonData = JsonConvert.SerializeObject(info);
            await _client.SendDataAsync(jsonData);
            var config = Configs.TcpClient;
            if(!_waitEvent.Wait(config.Timeout))
            {
                Log.WriteAsync("等待PaddleSeg处理超时.");
                return false;
            }
            else
            {
                Log.WriteAsync("等待PaddleSeg处理完成.");
                if(MapDestFiles.ContainsKey(info.Id))
                {
                    detecRes.SourceImagePath = MapDestFiles[info.Id];
                    MapDestFiles.TryRemove(info.Id, out _);
                    Log.WriteAsync($"处理原图变更为:{detecRes.SourceImagePath}.");
                    return true;
                }
                return false;
            }
        }
    }
}
